package com.lzy.filter;

import com.lzy.base.BaseInfoProperties;
import com.lzy.grace.result.ResponseStatusEnum;
import com.lzy.utils.IPUtil;
import com.lzy.utils.RenderErrorUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Slf4j
@RefreshScope
public class IPLimitFilter extends BaseInfoProperties implements GlobalFilter, Ordered {


    /*
     *  需求:
     *  判断某个请求的ip在20秒内的请求次数是否超过3次
     *  如果超过3次,则限制访问30秒
     *  等待30秒静默后,才能够继续访问
     */
    @Value("${blackIp.continueCounts}")
    private Integer continueCounts;

    @Value("${blackIp.timeInterval}")
    private Integer timeInterval;

    @Value("${blackIp.limitTimes}")
    private Integer limitTimes;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //log.info("当前执行顺序为1");
        //System.out.println("continueCounts:" + continueCounts);
        return dolimit(exchange,chain);
    }

    /*
     * 限制ip请求次数的判断
     */
    public Mono<Void> dolimit(ServerWebExchange exchange, GatewayFilterChain chain){

        // 1.根据request获取ip
        ServerHttpRequest request = exchange.getRequest();
        String ip = IPUtil.getIP(request);

        // 正常的ip定义
        final String ipRedisKey = "gateway-ip:" + ip;
        // 被拦截的黑名单ip,如果redis中存在,则表示被关进小黑屋
        final String ipRedisLimitKey = "gateway-ip-limit:" + ip;

        // 获得当前的ip并查询还剩多少时间，如果时间大于0,则表示仍存在于黑名单中
        long limitLeftTime = redis.ttl(ipRedisLimitKey);
        if(limitLeftTime > 0){
            // 终止请求,返回错误
            return RenderErrorUtils.display(exchange,ResponseStatusEnum.SYSTEM_ERROR_BLACK_IP);
        }

        // 在redis中获取ip的累加次数 -- 每请求一次redis的key-value增加一次
        long requestCounts = redis.increment(ipRedisKey,1);

        /**
         * 判断是否是第一次进来,如果是则从0开始计数
         * 需要设置间隔的时间,也就是连续请求的间隔时间
         */
        if(requestCounts == 1){
            redis.expire(ipRedisKey,timeInterval);
        }

        /**
         * 如果ipRedisKey生效期间访问次数超过了3次,
         * 则限制访问30秒
         */
        if(requestCounts > continueCounts){
            redis.set(ipRedisLimitKey,ipRedisLimitKey,limitTimes);
            //终止请求,返回错误信息
            return RenderErrorUtils.display(exchange,ResponseStatusEnum.SYSTEM_ERROR_BLACK_IP);
        }

        // 如果都没有问题,则放行
        return chain.filter(exchange);
    }

    //过滤器的顺序,顺序越小则优先级越大
    @Override
    public int getOrder() {
        return 1;
    }


}
